package com.spzx.product.service.impl;

import com.spzx.common.core.utils.StringUtils;
import com.spzx.product.service.TestService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * V1 测试数据库高并发 问题
     * 本地锁 解决不了分布式问题
     */
    @Override
    public synchronized void testLockV1() {
        // 查询Redis中的num值
        String value = this.stringRedisTemplate.opsForValue().get("num");
        // 没有该值return
        if (StringUtils.isBlank(value)) {
            return;
        }
        // 有值就转成int
        int num = Integer.parseInt(value);
        log.info("num:{}", num);
        // 把Redis中的num值+1
        this.stringRedisTemplate.opsForValue().set("num", String.valueOf(++num));
        log.info("num+1:{}", num);
    }


    /**
     * V2 测试数据库高并发 问题
     * 分布式锁 : 使用redis的setnx命令实现分布式锁
     */
    @Override
    public void testLockV2() {

        //尝试获取锁  :    等同于redis setnx lock 1命令
       Boolean flag = stringRedisTemplate.opsForValue().setIfAbsent("lock", "1");

       if (Boolean.TRUE.equals(flag)) {
          //业务代码
          String value = this.stringRedisTemplate.opsForValue().get("num");
          if (StringUtils.isBlank(value)) {
             return;
          }
          // 有值就转成int
          int num = Integer.parseInt(value);
          this.stringRedisTemplate.opsForValue().set("num", String.valueOf(++num));
           log.info("num:{}", num);

          //释放锁
          stringRedisTemplate.delete("lock");
        }else {
          // 没获取到锁 自旋等待
           log.info("没获取到锁 自旋等待");
           //递归调用 自己
           try {
               Thread.sleep(100);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }
           this.testLockV2();
       }

    }
}